#include "PathCoordinate.h"

#include "CellCoordinate.h"
#include "CatanClassContractException.h"

namespace catan
{

// Normalization shorthand (read conversion.txt for more)
// 
// .v-tr:
//     $ =    +0 -> .v-tr
// .v-tc:
//     $ = +v-tc -> .v-bc
// .v-tl:
//     $ =    +0 -> .v-tl
// .v-bl:
//     $ = +v-bl -> .v-tr
// .v-bc:
//     $ =    +0 -> .v-bc
// .v-br:
//     $ = +v-br -> .v-tl

/*static*/ bool PathCoordinate::canInit(CoordinateX coordinateX, CoordinateY coordinateY, VerticalCardinal verticalCardinal)
{
	if (CellCoordinate::canInit(coordinateX, coordinateY))
	{
		CellCoordinate parentCellCoordinate(coordinateX, coordinateY);
		
		switch (verticalCardinal.getEnum())
		{
		case VerticalCardinal::VERTICAL_TR:
		case VerticalCardinal::VERTICAL_TL:
		case VerticalCardinal::VERTICAL_BC:
			break;
		case VerticalCardinal::VERTICAL_TC:
			if (parentCellCoordinate.canCreateNeighbor(catan::verticalTC))
			{
				parentCellCoordinate = parentCellCoordinate.createNeighbor(catan::verticalTC);
				verticalCardinal = catan::verticalBC;
			}
			else
			{
				return false;
			}
			break;
		case VerticalCardinal::VERTICAL_BR:
			if (parentCellCoordinate.canCreateNeighbor(catan::verticalBR))
			{
				parentCellCoordinate = parentCellCoordinate.createNeighbor(catan::verticalBR);
				verticalCardinal = catan::verticalTL;
			}
			else
			{
				return false;
			}
			break;
		case VerticalCardinal::VERTICAL_BL:
			if (parentCellCoordinate.canCreateNeighbor(catan::verticalBL))
			{
				parentCellCoordinate = parentCellCoordinate.createNeighbor(catan::verticalBL);
				verticalCardinal = catan::verticalTR;
			}
			else
			{
				return false;
			}
			break;
		default:
			return false;
		}
	
		bool isMapCR = parentCellCoordinate.isOnGameMapEdge(catan::horizontalCR);
		bool isMapTR = parentCellCoordinate.isOnGameMapEdge(catan::horizontalTR);
		bool isMapTL = parentCellCoordinate.isOnGameMapEdge(catan::horizontalTL);
		bool isMapCL = parentCellCoordinate.isOnGameMapEdge(catan::horizontalCL);
		bool isMapBL = parentCellCoordinate.isOnGameMapEdge(catan::horizontalBL);
		bool isMapBR = parentCellCoordinate.isOnGameMapEdge(catan::horizontalBR);
		
		switch (verticalCardinal.getEnum())
		{
		case VerticalCardinal::VERTICAL_TR:
			return (!isMapCR && !isMapTR && !isMapTL && !isMapBR);
		case VerticalCardinal::VERTICAL_TL:
			return (!isMapTR && !isMapTL && !isMapCL && !isMapBL);
		case VerticalCardinal::VERTICAL_BC:
			return (!isMapCR && !isMapCL && !isMapBL && !isMapBR);
		default:
			return false;  // Should never happen.
		}
	}
	return false;
}

PathCoordinate::PathCoordinate(CoordinateX coordinateX, CoordinateY coordinateY, VerticalCardinal verticalCardinal) : BaseCoordinate(coordinateX, coordinateY), verticalCardinal(verticalCardinal)
{
	if (!PathCoordinate::canInit(coordinateX, coordinateY, verticalCardinal))
	{
		throw CatanClassContractException(__FILE__, __LINE__, "PathCoordinate::canInit(...) with constructor arguments should be true before creating instance.");
	}
	
	CellCoordinate parentCellCoordinate(coordinateX, coordinateY);
	switch (verticalCardinal.getEnum())
	{
	case VerticalCardinal::VERTICAL_TC:
		parentCellCoordinate = parentCellCoordinate.createNeighbor(catan::verticalTC);
		this->coordinateX = parentCellCoordinate.getCoordinateX();
		this->coordinateY = parentCellCoordinate.getCoordinateY();
		this->verticalCardinal = catan::verticalBC;
		break;
	case VerticalCardinal::VERTICAL_BL:
		parentCellCoordinate = parentCellCoordinate.createNeighbor(catan::verticalBL);
		this->coordinateX = parentCellCoordinate.getCoordinateX();
		this->coordinateY = parentCellCoordinate.getCoordinateY();
		this->verticalCardinal = catan::verticalTR;
		break;
	case VerticalCardinal::VERTICAL_BR:
		parentCellCoordinate = parentCellCoordinate.createNeighbor(catan::verticalBR);
		this->coordinateX = parentCellCoordinate.getCoordinateX();
		this->coordinateY = parentCellCoordinate.getCoordinateY();
		this->verticalCardinal = catan::verticalTL;
		break;
	default:
		break;
	}
}

VerticalCardinal PathCoordinate::getVerticalCardinal() const
{
	return verticalCardinal;
}

bool PathCoordinate::operator==(const PathCoordinate &other) const
{
	return (coordinateX == other.coordinateX && coordinateY == other.coordinateY && verticalCardinal == other.verticalCardinal);
}

bool PathCoordinate::operator<(const PathCoordinate &other) const
{
	return (
			(verticalCardinal < other.verticalCardinal || (verticalCardinal == other.verticalCardinal &&
					(coordinateY < other.coordinateY || (coordinateY == other.coordinateY &&
							(coordinateX < other.coordinateX)
					))
			))
	       );
}

PathCoordinate& PathCoordinate::operator=(const PathCoordinate& other)
{
    if (this != &other)
    {
        coordinateX = other.coordinateX;
        coordinateY = other.coordinateY;
        verticalCardinal = other.verticalCardinal;
    }
    return *this;	
}

}